﻿using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Threading;
using CommServer.Network;
using CommServer.Protocol;
using CommServer.Common.Json;
using System.Text;
using CommServer.Common;
using CommServer.Common.Database;
using System.Collections;

namespace CommServer.Controllers
{
    public class CollectController : Controller
    {
        [HttpGet]
        public object GetOnlineDevices()
        {
            DbResult<List<string>> Result = new DbResult<List<string>>();
            try
            {
                Result.data = new List<string>();
                DeviceServer deviceServer = Program.GetDeviceServer();
                List<TcpSession> Sessions = deviceServer.GetSessions();
                lock ((Sessions as ICollection).SyncRoot)
                {
                    foreach (var Session in Sessions)
                    {
                        if (Session.TagString != null && Session.TagString != "")
                        {
                            Result.data.Add(Session.TagString);
                        }
                    }
                }
                Result.state = 0;
                
            }
            catch (Exception ex)
            {
                Result.errMsg = ex.Message;
            }
            return Result;
        }

        [HttpPost]
        public object SyncClock(string RtuSN, string Time)
        {
            if (!HttpContext.Session.TryGetValue("UserId", out byte[] UserId))
            {
                DbResult Ret = new DbResult();
                Ret.state = (int)DbFailType.UserNotLogin;
                Ret.errMsg = "用户未登录";
                return Ret;
            }

            DateTime time = Convert.ToDateTime(Time);
            byte[] Data = new byte[6];
            Data[0] = (byte)(time.Year - 2000);
            Data[1] = (byte)(time.Month & 0xff);
            Data[2] = (byte)(time.Day & 0xff);
            Data[3] = (byte)(time.Hour & 0xff);
            Data[4] = (byte)(time.Minute & 0xff);
            Data[5] = (byte)(time.Second & 0xff);
            byte[] Frame = ProtocolPV.BuildMaintainFrame(0X36, Data);

            object Result = SendMaintainFrame(RtuSN, Frame, false);
            return Result;
        }
        /// <summary>
        /// 以通道列表和值列表的方式打开或关闭机器
        /// </summary>
        /// <param name="RtuSN">采集器SN</param>
        /// <param name="PlugAddr">插座地址六字节，12个字符，BCD码 </param>
        /// <param name="channels">通道列表，格式 1|2|...|N</param>
        /// <param name="values">值列表，格式 1|0|...|0，注意每一路通道的值只能是0或是1</param>
        /// <returns></returns>
        [HttpPost]
        
        public object OperatePlugsByChannels(string RtuSN, string PlugAddr, string channels, string values)
        {
            if (!HttpContext.Session.TryGetValue("UserId", out byte[] UserId))
            {
                DbResult Ret = new DbResult();
                Ret.state = (int)DbFailType.UserNotLogin;
                Ret.errMsg = "用户未登录";
                return Ret;
            }
            try
            {
                List<byte> Data = new List<byte>();
                PlugAddr = ("000000000000" + PlugAddr);
                PlugAddr = PlugAddr.Substring(PlugAddr.Length - 12);
                Data.AddRange(Util.HexToBytes(PlugAddr));
                string[] channs = channels.Split('|');
                string[] vals = values.Split('|');
                if (channs.Length != vals.Length)
                    throw new Exception("通道和值不匹配！");
                int[] channarray = new int[] { 0, 0, 0, 0,0,0,0,0 };
                int[] valuearray = new int[] { 0, 0, 0, 0,0,0,0,0 };
                string channelbits = "";
                string valuebits = "";
                
                for (int i =0;i<channs.Length;i++)
                {
                    string chan = channs[i];
                    int chanind = Convert.ToInt16(chan);
                    if ((chanind < 1) || (chanind > 8))
                        throw new Exception("通道号只能是1~4的数字");
                    channarray[chanind] = 1;
                    string val = vals[i];
                    if ((Convert.ToInt16(val) != 0) && (Convert.ToInt16(val) != 1))
                        throw new Exception("值必须为0或1");
                    valuearray[chanind] = Convert.ToInt16(val);
                }
               
                
                for (int i = 0; i < 8; i++)
                {
                    channelbits = channarray[i] + channelbits;
                    valuebits = valuearray[i] + valuebits;
                }
                
                byte SelectedChannels = Convert.ToByte(channelbits, 2);
                byte OperationBits = Convert.ToByte(valuebits, 2);
                //int channOperation = ((SelectedChannels & 0x0f) << 4) + (OperationBits & 0x0f);//协议版本中把两个字节合并为一个字节
                Data.Add((byte)SelectedChannels);
                Data.Add((byte)OperationBits);
                byte[] Frame = ProtocolPV.BuildMaintainFrame(0xFC, Data.ToArray());
                object Result = SendMaintainFrame(RtuSN, Frame, true);
                return Result;
            }
            catch(Exception ex)
            {
                DbResult Ret = new DbResult();
                Ret.state = -1;
                Ret.errMsg = "输入的参数有误，无法完成操作！系统错误信息："+ex.Message;
                return Ret;
            }
        }
        /// <summary>
        /// 以整数形式控制插座
        /// </summary>
        /// <param name="RtuSN">采集器SN</param>
        /// <param name="PlugAddr">插座地址，6字节，12字符，bcd码</param>
        /// <param name="SelectedChannels">拼好的通道整数，每一位代表一个通道位置，该位置为1，则表示对该通道进行控制
        ///  如1表示只控制第1通道，2表示只控制第2通道，3表示控制第1和2通道</param>
        /// <param name="OperationBits">接好的值，每一位代表一个通道位置，该位置为1，则表示打开该通道，为0表示关闭该通道 </param>
        /// <returns></returns>
        [HttpPost]
        public object OperatePlugs(string RtuSN, string PlugAddr,int SelectedChannels,int OperationBits)
        {
            if (!HttpContext.Session.TryGetValue("UserId", out byte[] UserId))
            {
                DbResult Ret = new DbResult();
                Ret.state = (int)DbFailType.UserNotLogin;
                Ret.errMsg = "用户未登录";
                return Ret;
            }
            List<byte> Data = new List<byte>();
            PlugAddr = ("000000000000" + PlugAddr);
            PlugAddr = PlugAddr.Substring(PlugAddr.Length - 12);
            Data.AddRange(Util.HexToBytes(PlugAddr));
            //int channOperation = ((SelectedChannels & 0x0f) << 4) + (OperationBits & 0x0f);//协议版本中把两个字节合并为一个字节
            Data.Add((byte)SelectedChannels);
            Data.Add((byte)OperationBits);
            byte[] Frame = ProtocolPV.BuildMaintainFrame(0xFC, Data.ToArray());
            object Result = SendMaintainFrame(RtuSN, Frame, true);
            return Result;
        }
        [HttpPost]
        public object transfer(string RtuSN, string data)
        {
            DbResult<string> Result = new DbResult<string>();
            byte[] bRole;
            if (!HttpContext.Session.TryGetValue("UserRole", out bRole))
            {
                Result.state = (int)ErrorCode.NoLogin;
                Result.errMsg = "用户未登录";
                return Result;
            }
            if (BitConverter.ToInt32(bRole, 0) > 0)
            {
                Result.state = (int)ErrorCode.NoAuth;
                Result.errMsg = "用户无权限，只有管理员才能设置参数！";
                return Result;
            }
            if (Program.GetDeviceServer().GetSession(RtuSN) == null)
            {
                Result.state = (int)ErrorCode.NotConnect;
                Result.errMsg = "设备不在线！";
                return Result;
            }
            data = data.Replace(" ", "");
            byte[] Frame = ProtocolPV.BuildMaintainFrame(0xF3,Util.HexToBytes( data));
            Log.Debug("Send:" + Util.BytesToHex(Frame));
            return SendMaintainFrame(RtuSN, Frame, true);
        }


        [HttpPost]
        public object StartClean(string RtuSN)
        {
            if (!HttpContext.Session.TryGetValue("UserId", out byte[] UserId))
            {
                DbResult Ret = new DbResult();
                Ret.state = (int)DbFailType.UserNotLogin;
                Ret.errMsg = "用户未登录";
                return Ret;
            }

            
            byte[] Data = new byte[1];
            Data[0] = 0x01;
            
            byte[] Frame = ProtocolPV.BuildMaintainFrame(0XF2, Data);

            object Result = SendMaintainFrame(RtuSN, Frame, false);
            return Result;
        }
        [HttpPost]
        public object CloseClean(string RtuSN)
        {
            if (!HttpContext.Session.TryGetValue("UserId", out byte[] UserId))
            {
                DbResult Ret = new DbResult();
                Ret.state = (int)DbFailType.UserNotLogin;
                Ret.errMsg = "用户未登录";
                return Ret;
            }


            byte[] Data = new byte[1];
            Data[0] = 0x00;

            byte[] Frame = ProtocolPV.BuildMaintainFrame(0XF2, Data);

            object Result = SendMaintainFrame(RtuSN, Frame, false);
            return Result;
        }

        [HttpPost]
        public object WriteBasicParams(string RtuSN, string RtuSNNew, string Server, ushort Port,
                                         string Apn, string UserName, string UserPwd, string DevPwd, byte InvType,
                                         List<dynamic> Meters)
        {
            if (!HttpContext.Session.TryGetValue("UserId", out byte[] UserId))
            {
                DbResult Ret = new DbResult();
                Ret.state = (int)DbFailType.UserNotLogin;
                Ret.errMsg = "用户未登录";
                return Ret;
            }
            //先读取，参数为null或者0的不设置
            Dictionary<string, object> Params = ReadBasicParams(RtuSN) as Dictionary<string, object>;
            if (Convert.ToInt32(Params["state"]) != 0)
            {
                return Params;
            }
            if (RtuSNNew == null)
            {
                RtuSNNew = Params["RtuSN"].ToString();
            }
            if (Server == null)
            {
                Server = Params["Server"].ToString();
            }
            if (Port == 0)
            {
                Port = Convert.ToUInt16(Params["Port"]);
            }
            if (Apn == null)
            {
                Apn = Params["Apn"].ToString();
            }
            if (UserName == null)
            {
                UserName = Params["UserName"].ToString();
            }
            if (UserPwd == null)
            {
                UserPwd = Params["UserPwd"].ToString();
            }
            if (DevPwd == null)
            {
                DevPwd = Params["DevPwd"].ToString();
            }
            if (InvType == 0)
            {
                InvType = Convert.ToByte(Params["InvType"]);
            }
            if (Meters.Count == 0)
            {
                Meters = Params["Meters"] as List<dynamic>;
            }
            List<byte> Data = new List<byte>();
            //组帧
            //ip25字节
            byte[] content = new byte[25];
            Encoding.ASCII.GetBytes(Server, 0, Server.Length, content, 0);
            Data.AddRange(content);
            //port2字节
            Data.AddRange(BitConverter.GetBytes(Port));
            //APN16字节
            content = new byte[16];
            Encoding.ASCII.GetBytes(Apn, 0, Apn.Length, content, 0);
            Data.AddRange(content);
            //UserName16字节
            content = new byte[16];
            Encoding.ASCII.GetBytes(UserName, 0, UserName.Length, content, 0);
            Data.AddRange(content);
            //UserPwd16字节
            content = new byte[16];
            Encoding.ASCII.GetBytes(UserPwd, 0, UserPwd.Length, content, 0);
            Data.AddRange(content);
            //RtuSNNew16字节
            content = new byte[16];
            Encoding.ASCII.GetBytes(RtuSNNew, 0, RtuSNNew.Length, content, 0);
            Data.AddRange(content);
            //DevPwd16字节
            content = new byte[32];
            Encoding.ASCII.GetBytes(DevPwd, 0, DevPwd.Length, content, 0);
            Data.AddRange(content);
            //InvType1字节
            Data.Add(InvType);
            //红外表 n*7
            for (int i = 0; i < Meters.Count; i++)
            {
                Data.AddRange(Util.HexToBytes(Meters[i].Addr));
                Data.Add(Convert.ToByte(Meters[i].Protocol));
            }

            byte[] Frame = ProtocolPV.BuildMaintainFrame(0xf0, Data.ToArray());
            object Result = SendMaintainFrame(RtuSN, Frame);
            return Result;
        }

        [HttpPost]
        public object ReadBasicParams(string RtuSN)
        {
            byte[] Frame = ProtocolPV.BuildMaintainFrame(0Xf1, new byte[0]);
            object Result = SendMaintainFrame(RtuSN, Frame);
            return Result;
        }

        [HttpPost]
        public object Reboot(string RtuSN)
        {
            object Result = SendMaintainFrame(RtuSN, null);
            return Result;
        }

        [HttpPost]
        public object RemoteUpgrade(string RtuSN, int PacketNo, int PacketTotal, string PacketData)
        {
            object Result = SendMaintainFrame(RtuSN, null);
            return Result;
        }


        private object SendMaintainFrame(string RtuSN, byte[] Frame, bool bRecv = true)
        {
            object SynObject = new object();
            Dictionary<string, object> Result = new Dictionary<string, object>();

            DeviceServer deviceServer = Program.GetDeviceServer();
            Action<byte[]> OnMaintainFrameReceive = null;

            ManualResetEventSlim signal = new ManualResetEventSlim(false);
            try
            {
                if (RtuSN == null || RtuSN == "")
                {
                    Result.Add("state", ErrorCode.ParamIncorrect);
                    Result.Add("errMsg", "参数不正确");
                    return Result;
                }
                TcpSession Session = deviceServer.GetSession(RtuSN);
                if (Session == null)
                {
                    Result.Add("state", ErrorCode.Offline);
                    Result.Add("errMsg", "采集器不在线");
                    return Result;
                }
                deviceServer.Send(Session, Frame);
                if (!bRecv)
                {
                    Result.Add("state", 0);
                    Result.Add("errMsg", "");
                    return Result;
                }

                bool b = false;
                OnMaintainFrameReceive = new Action<byte[]>((RFrame) =>
                {
                    //判断命令对应关系
                    b = (Frame[2] == RFrame[2]);

                    if (b)
                    {
                        signal.Set();
                        lock (SynObject)
                        {
                            ProtocolPV.FrameToObject(RFrame, Result);
                        }
                    }
                });

                deviceServer.OnMaintainFrameReceive += OnMaintainFrameReceive;
                signal.Wait(15000);
                lock (SynObject)
                {
                    if (!b)
                    {
                        Result.Add("state", ErrorCode.Timeout);
                        Result.Add("errMsg", "命令超时");
                        return Result;
                    }
                    Result.Add("state", 0);
                    Result.Add("errMsg", "");
                }

                return Result;
            }
            catch (Exception ex)
            {
                Result.Add("state", ErrorCode.SystemError);
                Result.Add("errMsg", ex.Message);
                return Result;
            }
            finally
            {
                signal.Dispose();
                if (OnMaintainFrameReceive != null)
                {
                    deviceServer.OnMaintainFrameReceive -= OnMaintainFrameReceive;
                }
            }
        }
    }
}
